#ifndef __SEMAPHORE_H__
#define __SEMAPHORE_H__

#include <chrono>
#include <mutex>
#include <condition_variable>



class Semaphore
{
public:
    Semaphore(int count = 0) : _count(count) {}

    void signal() {
        std::unique_lock<std::mutex> lock(_mutex);
        if (++_count <= 0) {
            _cv.notify_one();
        }
    }

    void signal_all() {
        std::unique_lock<std::mutex> lock(_mutex);
        _count = 0;
        _cv.notify_all();
    }

    void wait() {
        std::unique_lock<std::mutex> lock(_mutex);
        if (--_count < 0) {
            _cv.wait(lock);
        }
    }

    bool wait_for(int msec) {
        std::unique_lock<std::mutex> lock(_mutex);
        if (--_count >= 0) {
            return true;
        }
        chrono::milliseconds wait_time{msec};
        auto status = _cv.wait_for(lock, wait_time);
        if (status == std::cv_status::timeout) {
            _count++;
            return false;
        }
        return true;
    }

enum class cv_status {
    no_timeout,
    timeout  
};

private:
    std::mutex _mutex;
    std::condition_variable _cv;
    int _count;
};

#endif
